

package cn.shengchao.examstar.product.ohs.local.appservice;

import cn.hutool.core.util.StrUtil;
import cn.shengchao.base.enums.DisEnableStatusEnum;
import cn.shengchao.examstar.product.acl.adapters.repositories.factories.CourseFactory;
import cn.shengchao.examstar.product.acl.adapters.repositories.factories.CourseKnowledgeNodeFactory;
import cn.shengchao.examstar.product.acl.ports.repositories.ICourseRepository;
import cn.shengchao.examstar.product.acl.ports.repositories.IProductRepository;
import cn.shengchao.examstar.product.domain.entity.*;
import cn.shengchao.examstar.product.infrastructure.dao.ProductCourseNodesFreeUnlockDao;
import cn.shengchao.examstar.product.infrastructure.dao.po.ProductCourseNodesFreeUnlock;
import cn.shengchao.examstar.product.infrastructure.dao.po.TProductCourse;
import cn.shengchao.examstar.product.infrastructure.dao.po.TProductCourseNodes;
import cn.shengchao.examstar.product.ohs.local.message.CourseInfoDto;
import cn.shengchao.examstar.product.ohs.local.message.CourseListDto;
import cn.shengchao.examstar.product.ohs.local.message.KnowledgeNodeDto;
import cn.shengchao.examstar.rpc.product.req.CourseNodeConfig;
import cn.shengchao.examstar.rpc.product.req.SaveCourseInfo;
import cn.shengchao.examstar.rpc.product.req.SaveCourseNodes;
import cn.shengchao.examstar.rpc.product.res.BatchUnlockConfig;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.continew.starter.core.exception.BusinessException;
import top.continew.starter.core.validation.ValidationUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

@Slf4j
@Service
public class CourseService {

    @Autowired
    private IProductRepository iProductRepository;

    @Autowired
    private ICourseRepository iCourseRepository;

    @Autowired
    private AsyncTaskExecutor asyncTaskExecutor;

    @Autowired
    private ProductCourseNodesFreeUnlockDao productCourseNodesFreeUnlockDao;

    /**
     * 获取课程表
     */
    public List<CourseListDto> getCourseList(String name, String specifications, List<Long> ids) {
        List<Course> courses = iProductRepository.findCourseByProductNameAndSpecifications(name, specifications,ids);
        return getCourseListDto(courses);
    }

    /**
     * 获取课程表
     */
    public List<CourseListDto> getCourseListByIds(List<Long> ids) {
        log.info("获取课程列表：ids:{}", ids);
        List<Course> courses = iProductRepository.findCourseByIds(ids);
        return getCourseListDto(courses);
    }

    @NotNull
    private List<CourseListDto> getCourseListDto(List<Course> courses) {
        List<CourseListDto> courseListDtoList = courses.stream().map(CourseListDto::of).toList();
        List<CompletableFuture<Void>> teacher = courseListDtoList.stream()
                .map(course -> CompletableFuture.runAsync(() -> {
                    //获取老师
                    course.setTeacher(iProductRepository.findTeacherByCourseId(course.getId())
                            .stream()
                            .filter(teacherVo -> teacherVo.getId() != null)
                            .distinct()
                            .toList());
                    //获取知识点数量
                    course.setKnowledgeNodeNum((long) iProductRepository.findListByCourseId(course.getId(), "", true).size());
                }, asyncTaskExecutor))
                .toList();
        CompletableFuture.allOf(teacher.toArray(new CompletableFuture[0])).join();
        return courseListDtoList;
    }

    public CourseInfoDto getCourseInfo(Long courseId) {
        Optional<Product> productOptional = iProductRepository.findById(courseId);
        Product product = productOptional.orElseThrow(() -> new BusinessException("课程已下线！"));
        if (product instanceof Course course) {
            ValidationUtils.throwIf(product.getStatus().equals(DisEnableStatusEnum.DISABLE), "课程已下线！");
            CourseInfoDto courseInfoDto = CourseInfoDto.of(course);
            List<Teacher> teacher = iProductRepository.findTeacherByCourseId(courseId).stream().distinct().toList();
            courseInfoDto.setTeacher(teacher);
            return courseInfoDto;
        }
        return new CourseInfoDto();
    }

    //获取知识点列表
    public List<KnowledgeNodeDto> getKnowledgeList(Long courseId, String searchName, boolean isLesson) {
        List<CourseKnowledgeNode> courseKnowledgeNodes = iProductRepository.findListByCourseId(courseId, searchName, isLesson);
        return courseKnowledgeNodes.stream().map(KnowledgeNodeDto::of).toList();
    }

    public KnowledgeNodeDto getKnowledgeNodeDto(Long knowledgeNodeId) {
        CourseKnowledgeNode courseKnowledgeNode = iProductRepository.getKnowledgeNode(knowledgeNodeId);
        return KnowledgeNodeDto.of(courseKnowledgeNode);
    }

    public List<CourseListDto> getCourseListByTeacherId(Long teacherId) {
        log.info("获取老师课程：teacherId:{}", teacherId);
        List<Long> courseIds = iProductRepository.findCourseIdByTeacherId(teacherId);
        return getCourseListByIds(courseIds);
    }

    public void editCourse(SaveCourseInfo saveCourseInfo) {
        Course course = CourseFactory.of(saveCourseInfo);
        List<Long> specificationTypeIdList=new ArrayList<>();
        if(StrUtil.isNotBlank(saveCourseInfo.getSpecificationType())){
            List<String> specificationTypeIds = StrUtil.split(saveCourseInfo.getSpecificationType(), ",");
            specificationTypeIdList.addAll(specificationTypeIds.stream().map(Long::parseLong).toList());
            saveCourseInfo.setSpecificationType(specificationTypeIds.getFirst());
        }

        iCourseRepository.edit(course);
    }

    public Long editCourseNodes(SaveCourseNodes saveCourseNodes) {
        CourseKnowledgeNode courseKnowledgeNode = CourseKnowledgeNodeFactory.of(saveCourseNodes);
        TProductCourseNodes courseNodes = iCourseRepository.editCourseNodes(courseKnowledgeNode);
        return courseNodes.getId();
    }

    public SaveCourseNodes getCourseNode(Long nodeId) {
        CourseKnowledgeNode courseKnowledgeNode = iCourseRepository.getCourseNode(nodeId);
        SaveCourseNodes saveCourseNodes = new SaveCourseNodes();
        saveCourseNodes.setId(courseKnowledgeNode.getId());
        saveCourseNodes.setCourseId(courseKnowledgeNode.getCourseId());
        saveCourseNodes.setName(courseKnowledgeNode.getName().getValue());
        saveCourseNodes.setPrice(courseKnowledgeNode.getPrice().getPrice());
        saveCourseNodes.setDiscountPrice(courseKnowledgeNode.getDiscountPrice().getPrice());
        saveCourseNodes.setSort(courseKnowledgeNode.getSort());
        saveCourseNodes.setPlayUrl(courseKnowledgeNode.getPlayUrl());
        saveCourseNodes.setParentId(courseKnowledgeNode.getParentId());
        if (courseKnowledgeNode.getTeacher() != null) {
            saveCourseNodes.setTeacherId(courseKnowledgeNode.getTeacher().getId());
            saveCourseNodes.setTeacherName(courseKnowledgeNode.getTeacher().getName());
            saveCourseNodes.setTeacherHeadUrl(courseKnowledgeNode.getTeacher().getHeadUrl());
        }
        saveCourseNodes.setDuration(courseKnowledgeNode.getDuration());
        saveCourseNodes.setFileList(courseKnowledgeNode.getFileList());
        saveCourseNodes.setIsLesson(courseKnowledgeNode.getIsLesson());
        return saveCourseNodes;
    }

    public void deleteCourseNodes(Long nodeId) {
        iCourseRepository.deleteCourseNodes(nodeId);
    }

    public void deleteCourse(Long courseId) {
        iProductRepository.deleteCourse(courseId);
    }

    public void editCourseNodeConfig(CourseConfig courseConfig) {
        iCourseRepository.editCourseNodeConfig(courseConfig);
    }

    public CourseNodeConfig getCourseNodeConfig(Long courseId) {
        CourseConfig courseNodeConfig = iCourseRepository.getCourseNodeConfig(courseId);
        if (courseNodeConfig == null) {
            return new CourseNodeConfig();
        }
        CourseNodeConfig config = new CourseNodeConfig();
        if (courseNodeConfig.getFreeUnlockConfig() != null) {
            config.setId(courseNodeConfig.getFreeUnlockConfig().getId());
            config.setFreeUnlockSum(courseNodeConfig.getFreeUnlockConfig().getFreeUnlockSum());
        }
        config.setCourseId(courseNodeConfig.getCourseId());
        List<BatchUnlockConfig> configs = new ArrayList<>();
        for (DiscountConfig discountConfig : courseNodeConfig.getDiscountConfig()) {
            BatchUnlockConfig batchUnlockConfig = new BatchUnlockConfig();
            batchUnlockConfig.setId(discountConfig.getId());
            batchUnlockConfig.setCourseNodeSum(discountConfig.getCourseNodeSum());
            batchUnlockConfig.setDiscount(discountConfig.getDiscount());
            configs.add(batchUnlockConfig);
        }
        config.setBatchUnlockConfig(configs);
        return config;
    }

    public void updateCoursePrice(SaveCourseInfo saveCourseInfo) {
        iCourseRepository.updateCoursePrice(saveCourseInfo.getId(), saveCourseInfo.getPrice(), saveCourseInfo
                .getDiscountPrice());
    }

    public List<Long> getKnowledgeIds(Long courseId, boolean isLesson) {
        return iProductRepository.getKnowledgeIds(courseId, isLesson);
    }

    public Long getFreeUnlockSum(Long id) {
        ProductCourseNodesFreeUnlock productCourseNodesFreeUnlock = productCourseNodesFreeUnlockDao
                .selectOne(new LambdaQueryWrapper<ProductCourseNodesFreeUnlock>()
                        .eq(ProductCourseNodesFreeUnlock::getCourseId, id));
        if (productCourseNodesFreeUnlock == null) {
            return 0L;
        }
        return productCourseNodesFreeUnlock.getFreeUnlockSum();
    }

    public boolean isK12(Long courseId) {
        return iCourseRepository.isK12(courseId);
    }

    @Transactional
    public void changeStatus(Long courseId) {
        TProductCourse tProductCourse=iCourseRepository.ofCourse(courseId);
        if (tProductCourse.getStatus().equals(DisEnableStatusEnum.DISABLE)){
            tProductCourse.setStatus(DisEnableStatusEnum.ENABLE);
        }else if (tProductCourse.getStatus().equals(DisEnableStatusEnum.ENABLE)){
            tProductCourse.setStatus(DisEnableStatusEnum.DISABLE);
        }
        iCourseRepository.updateProductCourse(tProductCourse);
    }

    public List<KnowledgeNodeDto> getKnowledgeListByNewOrder(Long courseId, String searchName, boolean isLesson) {
        List<CourseKnowledgeNode> courseKnowledgeNodes = iProductRepository.findListByCourseId(courseId, searchName, isLesson);
        return courseKnowledgeNodes.stream().map(KnowledgeNodeDto::of).toList();
    }

    public List<Long> findGkCourseIdBySpecTag(String versionPrefix, String specTag) {
        return iCourseRepository.selectCourseIdsByPrefixSpecTag(versionPrefix, specTag);
    }

    public void updateCourseStatus(Long courseId, Integer status) {
        iCourseRepository.updateCourseStatusById(courseId, status);
    }
}
